{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Linear algebra"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'1.11.2'"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.__version__"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Matrix and vector products"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q1. Predict the results of the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[8 5]\n",
      "[6 6]\n",
      "[8 5]\n",
      "[6 6]\n",
      "[6 6]\n"
     ]
    }
   ],
   "source": [
    "x = [1,2]\n",
    "y = [[4, 1], [2, 2]]\n",
    "print np.dot(x, y)\n",
    "print np.dot(y, x)\n",
    "print np.matmul(x, y)\n",
    "print np.inner(x, y)\n",
    "print np.inner(y, x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q2. Predict the results of the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[4 1]\n",
      " [2 2]\n",
      " [1 1]]\n",
      "[[4 1]\n",
      " [2 2]\n",
      " [1 1]]\n"
     ]
    }
   ],
   "source": [
    "x = [[1, 0], [0, 1]]\n",
    "y = [[4, 1], [2, 2], [1, 1]]\n",
    "print np.dot(y, x)\n",
    "print np.matmul(y, x)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q3. Predict the results of the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "30\n",
      "30\n",
      "30\n",
      "30\n",
      "30\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1, 4], [5, 6]])\n",
    "y = np.array([[4, 1], [2, 2]])\n",
    "print np.vdot(x, y)\n",
    "print np.vdot(y, x)\n",
    "print np.dot(x.flatten(), y.flatten())\n",
    "print np.inner(x.flatten(), y.flatten())\n",
    "print (x*y).sum()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q4. Predict the results of the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "abb\n",
      "abb\n",
      "[['a' 'aa']\n",
      " ['b' 'bb']]\n",
      "[['a' 'b']\n",
      " ['aa' 'bb']]\n"
     ]
    }
   ],
   "source": [
    "x = np.array(['a', 'b'], dtype=object)\n",
    "y = np.array([1, 2])\n",
    "print np.inner(x, y)\n",
    "print np.inner(y, x)\n",
    "print np.outer(x, y)\n",
    "print np.outer(y, x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Decompositions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q5. Get the lower-trianglular `L` in the Cholesky decomposition of x and verify it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 2.  0.  0.]\n",
      " [ 6.  1.  0.]\n",
      " [-8.  5.  3.]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[4, 12, -16], [12, 37, -43], [-16, -43, 98]], dtype=np.int32)\n",
    "L = np.linalg.cholesky(x)\n",
    "print L\n",
    "assert np.array_equal(np.dot(L, L.T.conjugate()), x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q6. Compute the qr factorization of x and verify it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "q=\n",
      "[[-0.85714287  0.39428571  0.33142856]\n",
      " [-0.42857143 -0.90285712 -0.03428571]\n",
      " [ 0.2857143  -0.17142858  0.94285715]] \n",
      "r=\n",
      "[[ -14.  -21.   14.]\n",
      " [   0. -175.   70.]\n",
      " [   0.    0.  -35.]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[12, -51, 4], [6, 167, -68], [-4, 24, -41]], dtype=np.float32)\n",
    "q, r = np.linalg.qr(x)\n",
    "print \"q=\\n\", q, \"\\nr=\\n\", r\n",
    "assert np.allclose(np.dot(q, r), x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q7. Factor x by Singular Value Decomposition and verify it."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "U=\n",
      "[[ 0.  1.  0.  0.]\n",
      " [ 1.  0.  0.  0.]\n",
      " [ 0.  0.  0. -1.]\n",
      " [ 0.  0.  1.  0.]] \n",
      "s=\n",
      "[ 3.          2.23606801  2.          0.        ] \n",
      "V=\n",
      "[[ 1.  0.  0.]\n",
      " [ 0.  1.  0.]\n",
      " [ 0.  0.  1.]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1, 0, 0, 0, 2], [0, 0, 3, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0]], dtype=np.float32)\n",
    "U, s, V = np.linalg.svd(x, full_matrices=False)\n",
    "print \"U=\\n\", U, \"\\ns=\\n\", s, \"\\nV=\\n\", v\n",
    "assert np.allclose(np.dot(U, np.dot(np.diag(s), V)), x)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Matrix eigenvalues"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q8. Compute the eigenvalues and right eigenvectors of x. (Name them eigenvals and eigenvecs, respectively)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "eigenvalues are\n",
      "[ 1.  2.  3.]\n",
      "eigenvectors are\n",
      "[[ 1.  0.  0.]\n",
      " [ 0.  1.  0.]\n",
      " [ 0.  0.  1.]]\n"
     ]
    }
   ],
   "source": [
    "x = np.diag((1, 2, 3))\n",
    "eigenvals = np.linalg.eig(x)[0]\n",
    "eigenvals_ = np.linalg.eigvals(x)\n",
    "assert np.array_equal(eigenvals, eigenvals_)\n",
    "print \"eigenvalues are\\n\", eigenvals\n",
    "eigenvecs = np.linalg.eig(x)[1]\n",
    "print \"eigenvectors are\\n\", eigenvecs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q9. Predict the results of the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "print np.array_equal(np.dot(x, eigenvecs), eigenvals * eigenvecs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Norms and other numbers"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q10. Calculate the Frobenius norm and the condition number of x."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16.8819430161\n",
      "4.56177073661e+17\n"
     ]
    }
   ],
   "source": [
    "x = np.arange(1, 10).reshape((3, 3))\n",
    "print np.linalg.norm(x, 'fro')\n",
    "print np.linalg.cond(x, 'fro')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q11. Calculate the determinant of x."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-2.0\n"
     ]
    }
   ],
   "source": [
    "x = np.arange(1, 5).reshape((2, 2))\n",
    "out1 = np.linalg.det(x)\n",
    "out2 = x[0, 0] * x[1, 1] - x[0, 1] * x[1, 0]\n",
    "assert np.allclose(out1, out2)\n",
    "print out1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q12. Calculate the rank of x."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n"
     ]
    }
   ],
   "source": [
    "x = np.eye(4)\n",
    "out1 = np.linalg.matrix_rank(x)\n",
    "out2 = np.linalg.svd(x)[1].size\n",
    "assert out1 == out2\n",
    "print out1\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q13. Compute the sign and natural logarithm of the determinant of x."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-1.0 0.69314718056\n"
     ]
    }
   ],
   "source": [
    "x = np.arange(1, 5).reshape((2, 2))\n",
    "sign, logdet = np.linalg.slogdet(x)\n",
    "det = np.linalg.det(x)\n",
    "assert sign == np.sign(det)\n",
    "assert logdet == np.log(np.abs(det))\n",
    "print sign, logdet\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q14. Return the sum along the diagonal of x."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4.0\n"
     ]
    }
   ],
   "source": [
    "x = np.eye(4)\n",
    "out1 = np.trace(x)\n",
    "out2 = x.diagonal().sum()\n",
    "assert out1 == out2\n",
    "print out1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Solving equations and inverting matrices"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Q15. Compute the inverse of x."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[-2.   1. ]\n",
      " [ 1.5 -0.5]]\n"
     ]
    }
   ],
   "source": [
    "x = np.array([[1., 2.], [3., 4.]])\n",
    "out1 = np.linalg.inv(x)\n",
    "assert np.allclose(np.dot(x, out1), np.eye(2))\n",
    "print out1\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
